#include "Board.h"

Board::Board()
	: xMin(-70)
	, xMax(60)
	, zMin(-60)
	, zMax(70)
	, v3P1Start((float)xMin + (4*10), 0, (float)zMax - (4*10))
	, v3P2Start((float)xMin + (9*10), 0, (float)zMax - (9*10))
{
	m_iTextureIndex = 2;
}

void Board::WorldCoordToArrayIndex(int & x, int & z)
{
	// convert a coordinate in world space to what index it is on the board
	int XIndex = (x + (-1*xMin)) / 10;
	int ZIndex = (z + (-1*zMax)) / -10;

	x = XIndex;
	z = ZIndex;
}

bool Board::Init(int type, int owner, Vec3D pos)
{
	this->owner = owner;
	m_iType = type;
	m_iMeshIndex = type;
	m_v3Position = pos;

	return true;
}

void Board::CreateWorldTransform(D3DXMATRIX &matWorld)
{
	D3DXMatrixScaling(&m_matScale,							// prepare the scale matrix
							m_fScale, 
							m_fScale, 
							m_fScale);

	D3DXMatrixRotationYawPitchRoll(&m_matRotation,			// prepare the rotation matrix
										(float)m_rRotation.yaw, 
										(float)m_rRotation.pitch, 
										(float)m_rRotation.roll);

	D3DXMatrixTranslation(&m_matTrans,						// prepare the translation matrix
								m_v3Position.x, 
								m_v3Position.y, 
								m_v3Position.z);

	// combine the above matrices into the world matrix
	D3DXMatrixMultiply(&matWorld, &m_matScale, &m_matRotation);
	D3DXMatrixMultiply(&matWorld, &matWorld, &m_matTrans);
}

// check to see if piece can be put onto the board according to the game rules
bool Board::placePiece(Piece* toBePlaced)
{
	int xPos = (int)toBePlaced->getPos().x;
	int zPos = (int)toBePlaced->getPos().z;
	bool** shape = toBePlaced->m_bppShape;
	int player = toBePlaced->owner;
	bool cornersTouching = false;

	WorldCoordToArrayIndex(xPos, zPos);

	if(!toBePlaced->m_bFirstPiece)
	{
		// for each block in the piece
		for(int z = 0; z < toBePlaced->getSize(); z++)
		{
			for(int x = 0; x < toBePlaced->getSize(); x++)
			{
				if(shape[z][x] == true)
				{
					// only check the square above if the square is not at the top
					if(zPos + z != 0)
						if(BoardSlots[zPos + z-1][xPos+x] == player)
							return false;

					// only check the square below if the square is not at the top
					if(zPos + z != ciBoardHeight - 1)
						if(BoardSlots[zPos+z+1][xPos+x] == player)
							return false;

					// only check the square to the left if the current square is not already at the left side
					if(xPos + x != 0)
						if(BoardSlots[zPos+z][xPos+x-1] == player)
							return false;

					if(xPos + x != ciBoardWidth - 1)
						if(BoardSlots[zPos+z][xPos+x+1] == player)
							return false;

					if(zPos+z != 0 && xPos+x != 0)
						if(BoardSlots[zPos + (z-1)][xPos + (x-1)] == player)
							cornersTouching = true;

					if(zPos+z != ciBoardHeight-1 && xPos+x != ciBoardWidth-1)
						if(BoardSlots[zPos + (z+1)][xPos + (x+1)] == player)
							cornersTouching = true;

					if(zPos+z != 0 && xPos+x != ciBoardWidth-1)
						if(BoardSlots[zPos + (z-1)][xPos + (x+1)] == player)
							cornersTouching = true;

					if(zPos+z != ciBoardHeight-1 && xPos+x != 0)
						if(BoardSlots[zPos + (z+1)][xPos + (x-1)] == player)
							cornersTouching = true;

				}
			}
		}

		if(!cornersTouching)
			return false;
	}

	toBePlaced->m_bSelected = false;
	vPieces.push(toBePlaced);

	for(int z = 0; z < toBePlaced->getSize(); ++z)
	{
		for(int x = 0; x < toBePlaced->getSize(); ++x)
		{
			if(toBePlaced->m_bppShape[z][x] == true)
				BoardSlots[zPos + z][xPos + x] = toBePlaced->owner;
		}
	}

	return true;
}

void Board::Rotate(int direction)
{
}

void Board::findEmptySpot(Piece thePiece, int tilesToCheck, int &x, int &z)
{
	// if it's the first time through the function, set the position to 0
	if(tilesToCheck == 2)
	{
		x = z = 0;
		thePiece.MoveTo(x, z);
	}
	Direction dir;
	// check bottom
	dir.left = true;
	for(int i = 0; i < tilesToCheck; i++)
	{
		if(!isValidSpot(&thePiece))
			thePiece.Move(dir);
		else
		{
			x = (int)thePiece.getPos().x;
			z = (int)thePiece.getPos().z;
			return;
		}
	}
	// check left side
	dir.left = false;
	dir.up = true;
	for(int i = 0; i < tilesToCheck; i++)
	{
		if(!isValidSpot(&thePiece))
			thePiece.Move(dir);
		else
		{
			x = (int)thePiece.getPos().x;
			z = (int)thePiece.getPos().z;
			return;
		}
	}
	// check top
	dir.up = false;
	dir.right = true;
	for(int i = 0; i < tilesToCheck; i++)
	{
		if(!isValidSpot(&thePiece))
			thePiece.Move(dir);

		else
		{
			x = (int)thePiece.getPos().x;
			z = (int)thePiece.getPos().z;
			return;
		}
	}
	// check right side
	dir.right = false;
	dir.down = true;
	for(int i = 0; i < tilesToCheck; i++)
	{
		if(!isValidSpot(&thePiece))
			thePiece.Move(dir);

		else
		{
			x = (int)thePiece.getPos().x;
			z = (int)thePiece.getPos().z;
			return;
		}
	}
	
	// if a position could not be found within the spectrum of the board, flag x and z to be error values
	if(tilesToCheck > 14)
	{
		x = z = -1;
		return;
	}
	else
	{
		// move down and right and check the next set
		tilesToCheck += 2;
		dir.right = true;
		thePiece.Move(dir);

		// get the most recent coordindates
		x = (int)thePiece.getPos().x; 
		z = (int)thePiece.getPos().z;
		
		// run through the function again
		findEmptySpot(thePiece, tilesToCheck, x, z);
		if(x == -1 || z == -1)
			return;
	}

	return;
}

bool Board::isOutOfBounds(Piece* pieceInQuestion)
{
	int pieceSize = pieceInQuestion->getSize();	// store the size in a temp variable
	int xPos = (int)pieceInQuestion->getPos().x;
	int zPos = (int)pieceInQuestion->getPos().z;
	bool** shape = pieceInQuestion->m_bppShape;	// store the shape...
	bool valid = false;

	WorldCoordToArrayIndex(xPos, zPos);

	for(int z = 0; z < pieceSize; z++)
	{
		for(int x = 0; x < pieceSize; x++)
		{
			if(shape[z][x] == true &&	// if there is a block in this spot, and it's out of bounds
				(xPos + x < 0 || xPos + x > 13 ||
				 zPos + z < 0 || zPos + z > 13))
			{
				return true;		// return true, meaning that it is out of bounds	
			}
		}
	}

	// if the piece is the first piece to be played by the player, make sure it doesn't leave the starting area
	if(pieceInQuestion->m_bFirstPiece == true)
	{
		for(int z = 0; z < pieceSize; z++)
		{
			for(int x = 0; x < pieceSize; x++)
			{
				if(shape[z][x] == true &&									// if the piece has a block in this spot
					BoardSlots[zPos+z][xPos+x] == pieceInQuestion->owner)	// and the starting piece is also at the location
					return false;											// signal that the piece is is not out of bounds
			}
		}

		// if it's not touching the starting piece, signal that the piece has gone out of bounds
		return true;
	}
	
	// if we got to this point, return false saying that it is not out of bounds
	return false;
}

// determines whether or not the piece specified can fit in the board at its current location
bool Board::isValidSpot(Piece* pieceInQuestion)
{
	Piece temp(*pieceInQuestion);
	int pieceSize = pieceInQuestion->getSize();			// store the size in a temp variable
	int xPos = (int)pieceInQuestion->getPos().x;		// store the position in a temp variable
	int zPos = (int)pieceInQuestion->getPos().z;
	//bool** shape = temp.m_bppShape;			
	bool valid = true;

	WorldCoordToArrayIndex(xPos, zPos);

	// if it's not the first piece to be played
	if(!pieceInQuestion->m_bFirstPiece)
	{
		// check to see if a piece has collided with another piece already on the board
		for(int z = 0; z < pieceSize; z++)
		{
			for(int x = 0; x < pieceSize; x++)
			{
				// if the current slot on the board is occupied, and if the piece also has a block there, it's collided
				if(BoardSlots[zPos + z][xPos + x] != NOPLAYER &&
					temp.m_bppShape[z][x] == true)
				{
					valid = false;
					break;
				}
			}
		}
	}

	return valid;
}

void Board::Cleanup()
{
	vPieces.release();
	for(int y = 0; y < ciBoardHeight; ++y)
	{
		for(int x = 0; x < ciBoardWidth; ++x)
		{
			BoardSlots[y][x] = NOPLAYER;
		}
	}

	// set the starting spots for each player
	BoardSlots[4][4] = PLAYER1;
	BoardSlots[9][9] = PLAYER2;
}